#include <sys/timerfd.h>
#include <time.h>
#include <unistd.h>
#include "zemb/Timer.h"
#include "zemb/DateTime.h"
#include "zemb/Tracer.h"

namespace zemb{
Timer::Timer(const TimerListener& listener,int timerID):m_timerID(timerID)
{
    m_listener = const_cast<TimerListener*>(&listener);
}

Timer::~Timer()
{
}

bool Timer::start(int seconds, bool repeat)
{
    m_usInterval = seconds*1000000;
    m_repeat = repeat;
    m_startFlag = true;
    m_alarmTime = Time::fromEpoch();
    return true;
}
void Timer::stop()
{
    m_startFlag = false;
}

/* 比较时间 */
void Timer::checkAlarm()
{
    if (!m_startFlag)
    {
        return;
    }
    if (m_listener!=nullptr)
    {
        int diff = Time::usSinceMono(m_alarmTime);
        if (diff<m_usInterval)
        {
            return;
        }
        m_listener->onTimer(m_timerID);
        if (m_repeat)
        {
            int usOverTime = diff-m_usInterval;
            if (usOverTime<m_usInterval)
            {
                m_alarmTime = Time::fromMono()-Time(0,usOverTime);
            }
            else 
            {
                m_alarmTime = Time::fromMono();
            }
        }
        else
        {
            stop();
        }
    }

}

TimerManager::TimerManager()
{
    m_thread = std::make_unique<Thread>();
}

TimerManager::~TimerManager()
{
}

bool TimerManager::registerTimer(const Timer& timer)
{
    if (!m_startFlag)
    {
        if (!m_thread->start(*this))
        {
            return false;
        }
        m_startFlag = true;
    }
    Timer* pTimer = const_cast<Timer*>(&timer);
    AutoLock lock(m_tmrlstMutex);
    for(auto tmr : m_timerList)
    {
        if (tmr==pTimer)
        {
            return false;
        }
    }
    pTimer->m_startFlag=false;
    m_timerList.push_back(pTimer);
    return true;
}

bool TimerManager::unregisterTimer(const Timer& timer)
{
    Timer* pTimer = const_cast<Timer*>(&timer);
    AutoLock lock(m_tmrlstMutex);
    for(auto iter=m_timerList.begin();iter!=m_timerList.end();++iter)
    {
        if(*iter == pTimer)
        {
            m_timerList.erase(iter);
            return true;
        }
    }
    return false;
}

void TimerManager::run(Thread& thread)
{
    for(;;)
    {
        Thread::msleep(10);
        AutoLock lock(m_tmrlstMutex);
        for(auto tmr : m_timerList)
        {
            tmr->checkAlarm();
        }
    }
}

RTimer::RTimer(const TimerListener& listener,int id):
m_timerID(id)
{
    m_listener = const_cast<TimerListener*>(&listener);
}

RTimer::~RTimer()
{
    if (m_thread)
    {
        stop();
        m_thread = nullptr;
    }
}

bool RTimer::start(int msTimeout, bool repeat)
{
    if (msTimeout<=0 || m_timerID<0 || m_listener==nullptr)
    {
        TRACE_ERR_CLASS("param error, id:%d, timeout:%d, listener:0x%x",m_timerID,msTimeout, m_listener);
        return false;
    }
    m_repeat = repeat;
    m_usInterval = msTimeout*1000;
    m_usTick = CLIP(1000,m_usInterval/100,10000);/* 定时器tick,取值为[1000,10000],值越小线程负载越大,值越大精度越低 */
    m_thread = std::make_unique<Thread>();
    return m_thread->start(*this);
}

void RTimer::stop()
{
    if(m_thread)
    {
        m_thread->stop();
    }
}

void RTimer::run(Thread& thread)
{
    bool firstTime=true;
    Time lastTime,currTime;
    while (thread.isRunning()) 
    {
        if (firstTime)
        {
            lastTime = Time::fromMono();
            firstTime = false;
        }
        else
        {
            currTime = Time::fromMono();
            Time timeDiff = currTime-lastTime;
            int usOver = (int)(timeDiff.toMicroSec()) - m_usInterval;
            if(usOver>=0)/* 到了定时时间 */
            {
                //TRACE_DBG("RTimer usOver=%d",usOver);
                if (usOver>m_usInterval)
                {
                    //TRACE_WARN("RTimer over run interval: %d > %d",usOver,m_usInterval);
                    lastTime = currTime;/* 已经超过一个周期了,重新计算差值 */
                }
                else
                {
                    Time overTime(0,usOver);
                    lastTime = currTime-overTime;/* 减去超过的时间 */
                }
                
                if (m_listener!=nullptr)
                {
                    m_listener->onTimer(m_timerID);
                    if (!m_repeat)
                    {
                        break;
                    }
                }
            }
        }
        /* 每隔m_usTick读一次时间 */
        PThread::usleep(m_usTick);
    }
}

HRTimer::HRTimer(const TimerListener& listener,int id):
m_timerID(id)
{
    m_listener = const_cast<TimerListener*>(&listener);
}

HRTimer::~HRTimer()
{
    if (m_tmfd>0)
    {
        close(m_tmfd);
    }
    stop();
}

bool HRTimer::start(int usTimeout,bool repeat)
{
    if (usTimeout<=0)
    {
        return false;
    }

    if (m_tmfd<0)
    {
        m_tmfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC|TFD_NONBLOCK);
        if (m_tmfd<0)
        {
            return false;
        }
        if(!m_poller.open(1,false))
        {
            PRINT("poller open error!");
            return false;
        }
        PollEvent event(m_tmfd,PollEvent::POLLIN);
        if(!m_poller.addEvent(event))
        {
            PRINT("poller add Event error!");
            return false;
        }
    }

    itimerspec ts;
    Time value(usTimeout);//第一次超时时间
    ts.it_value.tv_sec = value.secPart();
    ts.it_value.tv_nsec = value.usPart()*1000;

    if (repeat)
    {
        Time interval(usTimeout);//重复时间间隔
        ts.it_interval.tv_sec = interval.secPart();
        ts.it_interval.tv_nsec = interval.usPart()*1000;
    }
    else
    {
        ts.it_interval.tv_sec = 0;
        ts.it_interval.tv_nsec = 0;
    }
    if(timerfd_settime(m_tmfd,0,&ts,NULL)<0)
    {
        return false;
    }

    m_usInterval = usTimeout;
    return m_thread.start(*this);
}

void HRTimer::stop()
{
    if (m_tmfd>0)
    {
        itimerspec ts;
        ts.it_value.tv_sec = 0;
        ts.it_value.tv_nsec = 0;
        ts.it_interval.tv_sec = 0;
        ts.it_interval.tv_nsec = 0;
        timerfd_settime(m_tmfd,0,&ts,NULL);
    }
    m_thread.stop();
}

void HRTimer::run(Thread& thread)
{
    int checkTime = m_usInterval/10;
    while (thread.isRunning()) 
    {
        auto events = m_poller.waitEvent(checkTime);
        if (events.size()>0)
        {
            uint64 timeoutCount = 0;
            int ret = read(m_tmfd,&timeoutCount,sizeof(timeoutCount));
            if (ret==sizeof(timeoutCount) && m_listener!=nullptr)
            {
                if (timeoutCount>1)
                {
                    PRINT_YELLOW("HRTimer::run, timer over run: %llu", timeoutCount);
                }
                m_listener->onTimer(m_timerID);
            }
        }
    }
}
}
